package gat.application.tg.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bitsun.core.common.exception.AppException;
import com.bitsun.core.common.exception.ErrorCode;
import com.bitsun.core.common.persistence.BasePService;
import com.bitsun.core.common.persistence.IPService;
import com.bitsun.core.common.persistence.Pager;
import com.bitsun.core.common.persistence.QueryParamUtils;
import com.google.common.base.CaseFormat;
import gat.RedisService;
import gat.application.tg.AccountOrderService;
import gat.application.tg.TgBotService;
import gat.common.util.CurrentThread;
import gat.common.util.ExportExcelUtil;
import gat.common.util.TelegramBot;
import gat.convertor.tg.AccountOrderReqDtoConvertor;
import gat.convertor.tg.AccountOrderResDtoConvertor;
import gat.domain.model.tp.TpAccountInfo;
import gat.domain.service.thirdParty.tp.TpFactory;
import gat.domain.service.thirdParty.tp.TpService;
import gat.dto.req.tg.AccountOrderReqDto;
import gat.dto.req.tg.AccountOrderReqParams;
import gat.dto.res.tg.AccountOrderResDto;
import gat.dto.res.tg.TgBotResDto;
import gat.infrastructure.persistence.dao.tg.AccountDbMapper;
import gat.infrastructure.persistence.dao.tg.AccountOrderMapper;
import gat.infrastructure.persistence.dao.tg.ChatBindRecordMapper;
import gat.infrastructure.persistence.po.tg.AccountDbPo;
import gat.infrastructure.persistence.po.tg.AccountOrderPo;
import gat.infrastructure.persistence.po.tg.ChatBindRecordPo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
 * 示例表，应用（业务编排）层实现
 * @author: yanshukeji-java
 * @email: yanshukeji-java
 */
@Slf4j
@Service("accountOrderAppService")
@Transactional(rollbackFor = Exception.class)
public class AccountOrderServiceImpl implements AccountOrderService {

    @Autowired
    private AccountOrderReqDtoConvertor accountOrderReqDtoConvertor;

    @Autowired
    private AccountOrderResDtoConvertor accountOrderResDtoConvertor;

    @Autowired
    private TgBotService tgBotService;

    @Autowired
    private TpFactory tpFactory;

    @Autowired
    private AccountDbMapper accountDbMapper;

    @Autowired
    private ChatBindRecordMapper chatBindRecordMapper;

    @Autowired
    private RedisService redisService;

    private IPService<AccountOrderPo> accountOrderPoService;

    @SuppressWarnings("SpringJavaAutowiringInspection")
    public AccountOrderServiceImpl(AccountOrderMapper accountOrderMapper) {
        this.accountOrderPoService = new BasePService(accountOrderMapper);
    }



    @Override
    public AccountOrderResDto save(AccountOrderReqDto reqDto) {
        AccountOrderPo po = accountOrderReqDtoConvertor.dto2Po(reqDto);
        accountOrderPoService.save(po);
        AccountOrderResDto resDto = accountOrderResDtoConvertor.po2Dto(po);
        return resDto;
    }

    @Override
    public boolean deleteByIds(String ids) {
        try {
            List<Long> idLongList =
            Arrays.asList(ids.split(",")).stream().map(s -> NumberUtils.createLong(s.trim())).collect(Collectors.toList());
            return accountOrderPoService.removeByIds(idLongList);
        } catch (Exception e) {
            throw new AppException("参数错误：" + ids, ErrorCode.pc("417"), e);
        }
     }

    @Override
    public Pager<AccountOrderResDto> doPager(Map<String, Object> params) {
        Pager<AccountOrderPo> poPager = accountOrderPoService.queryPage(params, AccountOrderPo.class);
        Pager<AccountOrderResDto> resDtoPager = accountOrderResDtoConvertor.convertPoPager2ResDtoPager(poPager);
        return resDtoPager;
    }

    @Override
    public AccountOrderResDto selectOne(Long id) {
        AccountOrderPo po = accountOrderPoService.getById(id);
        AccountOrderResDto resDto = accountOrderResDtoConvertor.po2Dto(po);
        return resDto;
    }

    @Override
    public AccountOrderResDto selectOne(Map<String, Object> params) {
        QueryWrapper queryWrapper = QueryParamUtils.queryWrapper4eq(AccountOrderPo::new, params);
        queryWrapper.last(" limit 1");
        AccountOrderPo po = accountOrderPoService.getOne(queryWrapper);
        AccountOrderResDto resDto = accountOrderResDtoConvertor.po2Dto(po);
        return resDto;
    }

    @Override
    public boolean updateProps(Long id, Map<String, Object> params) {
        UpdateWrapper<AccountOrderPo> updateWrapper = QueryParamUtils.updateWrapper4Map(AccountOrderPo::new, id, params);
        return accountOrderPoService.update(new AccountOrderPo(), updateWrapper);
        }

    @Override
    public boolean updateProps(Long id, AccountOrderReqDto reqDto) {
        AccountOrderPo po = accountOrderReqDtoConvertor.dto2Po(reqDto);
        po.setId(id);
        return accountOrderPoService.updateById(po);
    }

    @Override
    public void updateStatus(Long id) {
        AccountOrderPo accountOrder = accountOrderPoService.getById(id);
        if (accountOrder == null) {
            return;
        }

        TgBotResDto tgBot =tgBotService.getTgBotByBotUni(accountOrder.getBotId());
        if (tgBot == null) {
            return;
        }
        if (accountOrder.getOrderStatus() != 1) {
            TpService service = tpFactory.getService(accountOrder.getAccountSupplier());

            AccountDbPo accountDb = accountDbMapper.selectOne(new LambdaQueryWrapper<AccountDbPo>()
                    .eq(AccountDbPo::getAccountId, accountOrder.getAccountId())
                    .eq(AccountDbPo::getAccountSupplier, accountOrder.getAccountSupplier())
            );

            TpAccountInfo tpAccountInfo = service.queryAccountInfo(accountDb.getAccountId());

            if (StringUtils.equals(accountDb.getSource(), "api") || accountOrder.getOrderType() == 2 || accountDb.getAccountType().equals("普通")) {
                service.transferCredit(accountOrder.getAccountId(), accountOrder.getOriginalPrice());
                tpAccountInfo = service.queryAccountInfo(accountDb.getAccountId());
            }
            accountOrder.setOrderStatus(1);
            accountOrder.setPayTime(LocalDateTime.now());
            accountOrderPoService.updateById(accountOrder);


            long chatId = Long.parseLong(accountOrder.getChatId());
            long tgUser = Long.parseLong(accountOrder.getTgUserId());

            BigDecimal creditLine = new BigDecimal(tpAccountInfo.getCreditLine());
            creditLine = creditLine.divide(new BigDecimal("1000000"), 6, RoundingMode.HALF_UP);

            BigDecimal availableCredit = new BigDecimal(tpAccountInfo.getAvailableCredit());
            availableCredit = availableCredit.divide(new BigDecimal("1000000"), 6, RoundingMode.HALF_UP);

            // 这里处理两种情况 申请认证账号 和 申请普通账号 后者算到充值业务中 订单类型属于充值类型 这里用账号状态为锁定状态来判断 因为正常充值业务都是已分配的账号
            if (accountOrder.getOrderType() == 1 || accountDb.getStatus() == 2) {
                if (accountDb.getAccountSupplier().equals("tencent") ) {
                    service.forceQN(accountOrder.getAccountId(), 0);
                }
                accountDb.setStatus(1);
                accountDb.setBotId(accountOrder.getBotId());
                accountDbMapper.updateById(accountDb);

                String message = String.format(
                        "✅ 您的订单号 %s 已完成支付，已为您分配账号：" + System.lineSeparator() + System.lineSeparator()
                                + "☁️ 云厂商：%s" + System.lineSeparator()
                                + "🆔 客户ID：%s" + System.lineSeparator()
                                + "📧 账号邮箱：%s" + System.lineSeparator()
                                + "🔑 账号密码：%s" + System.lineSeparator()
                                + "📨 邮箱密码：%s" + System.lineSeparator()
                                + "📱 联系手机：%s" + System.lineSeparator()
                                + "💳 总信用额：%s" + System.lineSeparator()
                                + "💰 剩余额度：%s" + System.lineSeparator()
                                + "🌐 邮箱登录地址：%s",
                        accountOrder.getOrderNo(),
                        accountOrder.getAccountSupplier().equals("ali") ? "阿里云" : "腾讯云",
                        accountDb.getAccountId(),          // 客户ID：5110234500412164
                        accountDb.getAccountMail(),        // 账号邮箱：ailyy@plmyh.com
                        accountDb.getAccountPassword(),    // 账号密码：&,Eridat,54
                        accountDb.getMailPassword(),       // 邮箱密码：&,Eridat,54
                        tpAccountInfo.getPhone(),       // 联系手机：66-968010272
                        creditLine,        // 总信用额：0.000000
                        availableCredit,    // 剩余额度：0.000000
                        accountDb.getMailLoginUrl()        // 邮箱登录地址：https://www.plmyh.com/SOGo/
                );

                if (accountOrder.getChatType().equals("group")) {
                    TelegramBot.sendMessageToGroup(tgBot.getToken(), chatId, tgUser, accountOrder.getTgUserName(), message);
                } else {
                    TelegramBot.sendMessageToPrivate(tgBot.getToken(), chatId, message);
                }
            } else {
                accountDb.setStatus(1);
                accountDb.setBotId(accountOrder.getBotId());
                accountDbMapper.updateById(accountDb);

                String message = String.format(
                        "✅ 您的订单号 %s 已完成支付，已为您成功充值：" + System.lineSeparator() + System.lineSeparator()
                                + "☁️ 云厂商：%s" + System.lineSeparator()
                                + "🆔 客户ID：%s" + System.lineSeparator()
                                + "📧 账号邮箱：%s" + System.lineSeparator()
                                + "📱 联系手机：%s" + System.lineSeparator()
                                + "💳 总信用额：%s" + System.lineSeparator()
                                + "💰 剩余额度：%s" + System.lineSeparator(),
                        accountOrder.getOrderNo(),
                        accountOrder.getAccountSupplier().equals("ali") ? "阿里云" : "腾讯云",
                        accountDb.getAccountId(),          // 客户ID：5110234500412164
                        accountDb.getAccountMail(),        // 账号邮箱：ailyy@plmyh.com
                        tpAccountInfo.getPhone(),       // 联系手机：66-968010272
                        creditLine,        // 总信用额：0.000000
                        availableCredit    // 剩余额度：0.000000

                );

                // 针对腾讯云需要处理 对于冻结账号 剩余信控额度大于0 之后需要解冻
                if (accountDb.getAccountSupplier().equals("tencent") && !tpAccountInfo.getAccountStatus().equals("normal") && tpAccountInfo.getAvailableCredit() > 0) {
                    service.forceQN(accountOrder.getAccountId(), 0);
                }

                if (accountOrder.getChatType().equals("group")) {
                    TelegramBot.sendMessageToGroup(tgBot.getToken(), chatId, tgUser, accountOrder.getTgUserName(), message);
                } else {
                    TelegramBot.sendMessageToPrivate(tgBot.getToken(), chatId, message);
                }
            }

            // 把业务设计的账号 放入绑定记录中

            ChatBindRecordPo chatBindRecordPo = chatBindRecordMapper.selectOne(new LambdaQueryWrapper<ChatBindRecordPo>()
                    .eq(ChatBindRecordPo::getChatId, accountOrder.getChatId())
                    .eq(ChatBindRecordPo::getChatType, accountOrder.getChatType())
                    .eq(ChatBindRecordPo::getBindAccountId, accountOrder.getAccountId())
                    .eq(ChatBindRecordPo::getAccountSupplier, accountOrder.getAccountSupplier())
            );

            ChatBindRecordPo chatBindRecord = new ChatBindRecordPo();
            chatBindRecord.setChatId(accountOrder.getChatId());
            chatBindRecord.setChatType(accountOrder.getChatType());
            chatBindRecord.setAccountSupplier(accountOrder.getAccountSupplier());
            chatBindRecord.setBindAccountId(accountOrder.getAccountId());
            if (chatBindRecordPo == null) {
                chatBindRecord.setCreateTime(LocalDateTime.now());
                chatBindRecord.setBindUserId(accountOrder.getTgUserId());
                chatBindRecord.setWarningBalance(20000000L);
                chatBindRecord.setTgUserName(accountOrder.getTgUserName());
                chatBindRecord.setBotId(accountOrder.getBotId());
                chatBindRecordMapper.insert(chatBindRecord);
                redisService.del("account");
            }
        }
    }


    @Override
    public boolean updateAllProps(Long id, AccountOrderReqDto reqDto) {
        UpdateWrapper<AccountOrderPo> updateWrapper = Wrappers.update();
        updateWrapper.eq("id", id);
        Field[] fields = AccountOrderReqDto.class.getDeclaredFields();
        Arrays.stream(fields).filter(f -> !Modifier.isStatic(f.getModifiers())).forEach(field -> {
        try {
        PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), AccountOrderReqDto.class);
        Method getMethod = propertyDescriptor.getReadMethod();
        String fileNameCamel = getMethod.getName().substring(3);
        String fileNameUnderline = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fileNameCamel);
        updateWrapper.set(fileNameUnderline, getMethod.invoke(reqDto));
        } catch (Exception ex) {
        log.warn("属性不存在get方法："+field.getName(),ex);
        }
        });
        return accountOrderPoService.update(new AccountOrderPo(), updateWrapper);
    }

    @Override
    public Pager<AccountOrderResDto> queryPage(AccountOrderReqParams params) {
        String username = CurrentThread.getCurrentUser().getUsername();
        if (!StringUtils.equals(username, "admin") && StringUtils.isEmpty(params.getBotId())) {
            throw new AppException("参数错误：机器人id不能为空");
        }
        if (ObjectUtil.isNotNull(params.getStartTime()) ) {
            params.setStartTime(params.getStartTime() + " 00:00:01");
        }
        if (ObjectUtil.isNotNull(params.getEndTime())) {
            params.setEndTime(params.getEndTime() + " 23:59:59");
        }

        IPage<AccountOrderPo> iPage =
                accountOrderPoService.page(new Page<>(params.getCurrentPage(), params.getPageSize()),
                        new LambdaQueryWrapper<AccountOrderPo>()
                                .ne(Objects.nonNull(params.getStartTime()), AccountOrderPo::getCreateTime, params.getStartTime())
                                .le(Objects.nonNull(params.getEndTime()), AccountOrderPo::getCreateTime, params.getEndTime())
                                .eq(StringUtils.isNotBlank(params.getAccountId()), AccountOrderPo::getAccountId, params.getAccountId())
                                .eq(StringUtils.isNotBlank(params.getAccountSupplier()), AccountOrderPo::getAccountSupplier, params.getAccountSupplier())
                                .eq(ObjectUtil.isNotEmpty(params.getOrderType()), AccountOrderPo::getOrderType, params.getOrderType())
                                .eq(ObjectUtil.isNotEmpty(params.getOrderStatus()), AccountOrderPo::getOrderStatus, params.getOrderStatus())
                                .eq(StringUtils.isNotBlank(params.getTgUserName()), AccountOrderPo::getTgUserId, params.getTgUserName())
                                .eq(StringUtils.isNotBlank(params.getOrderNo()), AccountOrderPo::getOrderNo, params.getOrderNo())
                                .eq(StringUtils.isNotBlank(params.getChatType()), AccountOrderPo::getChatType, params.getChatType())
                                .eq(StringUtils.isNotBlank(params.getPrimaryUid()), AccountOrderPo::getPrimaryUid, params.getPrimaryUid())
                                .eq(StringUtils.isNotBlank(params.getBotId()), AccountOrderPo::getBotId, params.getBotId())
                                .orderByDesc(AccountOrderPo::getCreateTime)

                );
        return accountOrderResDtoConvertor.convertPoPager2ResDtoPager(
                new Pager<>(iPage.getRecords(), iPage.getTotal(), params.getPageSize(), iPage.getCurrent()));
    }

    @Override
    public void exportOrders(HttpServletResponse response, AccountOrderReqParams params) {

        String username = CurrentThread.getCurrentUser().getUsername();
        if (!StringUtils.equals(username, "admin") && StringUtils.isEmpty(params.getBotId())) {
            throw new AppException("参数错误：机器人id不能为空");
        }
        if (ObjectUtil.isNotNull(params.getStartTime()) ) {
            params.setStartTime(params.getStartTime() + " 00:00:01");
        }
        if (ObjectUtil.isNotNull(params.getEndTime())) {
            params.setEndTime(params.getEndTime() + " 23:59:59");
        }


        List<AccountOrderPo> orderPos = accountOrderPoService.list(new LambdaQueryWrapper<AccountOrderPo>()
                .ne(Objects.nonNull(params.getStartTime()), AccountOrderPo::getCreateTime, params.getStartTime())
                .le(Objects.nonNull(params.getEndTime()), AccountOrderPo::getCreateTime, params.getEndTime())
                .eq(StringUtils.isNotBlank(params.getAccountId()), AccountOrderPo::getAccountId, params.getAccountId())
                .eq(StringUtils.isNotBlank(params.getAccountSupplier()), AccountOrderPo::getAccountSupplier, params.getAccountSupplier())
                .eq(ObjectUtil.isNotEmpty(params.getOrderType()), AccountOrderPo::getOrderType, params.getOrderType())
                .eq(ObjectUtil.isNotEmpty(params.getOrderStatus()), AccountOrderPo::getOrderStatus, params.getOrderStatus())
                .eq(StringUtils.isNotBlank(params.getTgUserName()), AccountOrderPo::getTgUserId, params.getTgUserName())
                .eq(StringUtils.isNotBlank(params.getOrderNo()), AccountOrderPo::getOrderNo, params.getOrderNo())
                .eq(StringUtils.isNotBlank(params.getChatType()), AccountOrderPo::getChatType, params.getChatType())
                .eq(StringUtils.isNotBlank(params.getPrimaryUid()), AccountOrderPo::getPrimaryUid, params.getPrimaryUid())
                .eq(StringUtils.isNotBlank(params.getBotId()), AccountOrderPo::getBotId, params.getBotId())
                .orderByDesc(AccountOrderPo::getCreateTime));


        List<AccountOrderResDto> accountOrderResDtos = accountOrderResDtoConvertor.poList2DtoList(orderPos);


        String fileName = "订单导出" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        try {
            ExportExcelUtil.downloadExcel(response, AccountOrderResDto.class, fileName, "订单表", accountOrderResDtos);
        } catch (IOException e) {
            log.error("导出订单失败", e);
        }

    }

    @Override
    public void updatePrice(Long id, AccountOrderReqDto accountOrderReqDto) {
        AccountOrderPo accountOrderPo = accountOrderPoService.getById(id);
        if (ObjectUtil.isNull(accountOrderPo)) {
            throw new AppException("订单不存在");
        }
        if (accountOrderPo.getOrderStatus() != 1) {
            throw new AppException("订单未完成支付，暂不允许修改金额");
        }
        accountOrderPo.setDiscount(accountOrderReqDto.getDiscount());

        BigDecimal discount = BigDecimal.valueOf(accountOrderReqDto.getDiscount()).divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP);

        // 使用BigDecimal进行精确计算
        BigDecimal result = BigDecimal.valueOf(accountOrderPo.getOrderAmount())
                .divide(discount, 2, RoundingMode.HALF_UP);

        accountOrderPo.setOriginalPrice(result.longValue());

        accountOrderPoService.updateById(accountOrderPo);
    }

}